/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

package ruptela;

/**
 *
 * @author Bartlomiej Zeslawski, Globtrak Polska Sp. z o. o.
 */
import java.io.Serializable;
import javax.smartcardio.ATR;
import javax.smartcardio.Card;
import javax.smartcardio.CardChannel;
import javax.smartcardio.CardException;
import javax.smartcardio.CardTerminal;
import javax.smartcardio.CommandAPDU;
import javax.smartcardio.ResponseAPDU;

public class TerminalCard {
    private CardTerminal MyCardTerminal;
    private Card MyCard = null;
    private byte[] MagicArray = new byte[]{-74, -80, 73, 42, -21, -41, -16, -15, -30, -6, -33, 50, 102, 108, 66, 127, 97, 114, -87, 21, -70, 32, -7, -17, 116, 90, 57, -85, 8, -53, -97, -117, 63, -60, -66, -43, 88, -86, 57, 89, 49, 27, 36, -17, -44, 79, 38, 117, -51, -23, 26, 79, 56, 122, 96, -112, 10, 47, 96, 97, 60, 82, 113, 29, 18, 91, -80, -110, -80, 78, 16, 127, -97, -119, 23, 100, 21, -28, 36, -100, -10, -43, -100, -94, -43, -82, 102, -78, -76, 65, 79, 18, -14, 19, 81, 23, -128, -45, -85, -57, -68, -25, 51, -22, 89, -3, 127, -78, 86, -66, -16, -61, 63, 2, 61, 76, 93, -88, -17, 117, 8, -56, -63, -99, 124, -70, -115, -54, -55, 83, 121, 12, -76, -73, -82, 10, -100, -12, -86, -17, -122, -92, 11, -54, -89, 47, -77, -55, -75, -24, 64, -39, -114, -77, -50, -105, -54, 45, -127, -103, 78, -72, 110, -34, -44, 2, -85, -63, 29, 74, 71, -16, 40, 13, 62, -81, 120, -109, 105, -98, 25, -124, 85, -110, -56, 52, 69, -100, 49, 4, 36, 3, 27, -44, 80, 81, 75, 107, 100, 19, -3, -30, 37, 84, 98, 108, 5, 36, -26, 84, 72, -120, 109, 87, -98, 35, -83, -113, -88, 127, -30, 58, 15, -65, -109, 64, 61, -75, 103, 94, -29, -70, -96, 59, -103, -19, 122, 86, 93, -116, 91, -87, -41, 99, 105, 7, 70, 29, -79, -112, 53, 69, 102, 73, -115, 16};

    public TerminalCard(CardTerminal cardTerminal) throws CardException {
        System.setProperty("sun.security.smartcardio.t0GetResponse", "false");
        this.MyCardTerminal = cardTerminal;
        this.connect();
        byte[] byteArr = new byte[]{0, -92, 4, 12, 6, -1, 84, 65, 67, 72, 79};
        byte[] arrby = communicate(byteArr);
        
        if (arrby.length != 2 || arrby[0] != -112 || arrby[1] != 0) {
            throw new CardException("The card is not Tacho");
        }
        this.disconnect();
    }

    public String getTerminalName() {
        return this.MyCardTerminal.getName();
    }

    public void connect() throws CardException {
        this.MyCard = this.MyCardTerminal.connect("T=0");
    }

    public void disconnect() {
        this.disconnectCard(false);
    }

    private void disconnectCard(boolean bl) {
        if (System.getProperty("java.version").startsWith("1.7.")) {
            bl = false;
        }
        if (this.MyCard instanceof Card) {
            try {
                this.MyCard.disconnect(bl);
            }
            catch (CardException v0) {}
        }
        this.MyCard = null;
    }

    public boolean isConnected() {
        try {
            if (this.MyCard instanceof Card && this.MyCardTerminal.isCardPresent()) {
                return true;
            }
        }
        catch (CardException v0) {}
        return false;
    }

    public byte[] getATR() throws CardException {
        try {
            this.disconnectCard(true);
            this.connect();
            return this.MyCard.getATR().getBytes();
        }
        catch (Exception v0) {
            throw new CardException("Card not connected");
        }
    }

    public byte[] request(byte[] array) throws CardException {
        return prepareData(swapBytes(communicate(swapBytes(prepareData(array)))));
    }

    private byte[] communicate(byte[] arrby) throws CardException {
        CardChannel cardChannel = MyCard.getBasicChannel();
        if (arrby.length > 2) {
            boolean bl = true;
            byte n = 0;
            if (arrby.length == 14 && arrby[0] == 12 && arrby[1] == -80) {
                n = 0;
                bl = false;
            } else if (arrby.length == 21 && arrby[0] == 0 && arrby[1] == -120) {
                n = -128;
                bl = false;
            }
            if (!bl) {
                byte[] arrby2 = new byte[arrby.length + 1];
                System.arraycopy(arrby, 0, arrby2, 0, arrby.length);
                arrby2[arrby.length] = n;
                arrby = (byte[])arrby2.clone();
            }
        }
        CommandAPDU cmd = new CommandAPDU(arrby);
        arrby = cardChannel.transmit(cmd).getBytes();
        if (arrby.length == 2 && arrby[0] == 97) {
            byte[] arrby3 = new byte[]{0, -64, 0, 0, arrby[1]};
            arrby = cardChannel.transmit(new CommandAPDU(arrby3)).getBytes();
        }
        return arrby;
    }

    private byte[] prepareData(byte[] arrby) {
        for (int i = 0; i < arrby.length; ++i) {
            arrby[i] ^= MagicArray[i % MagicArray.length];
        }
        return arrby;
    }

    private static byte[] swapBytes(byte[] arrby) {
        int len = arrby.length;
        if (len > 1) {
            byte by2 = arrby[0];
            arrby[0] = arrby[len - 1];
            arrby[len - 1] = by2;
        }
        return arrby;
    }
}


